package ecode

import (
	"fmt"
	"runtime"
	"strings"
)

const stackDepth = 20

// GetPanicTrace
func GetPanicTrace(serviceName string, r interface{}) string {
	buf := make([]byte, 64<<10)
	buf = buf[:runtime.Stack(buf, false)]
	stackLines := make([]string, 0)
	methodCache := ""
	// 格式化stackTrace，仅保留需要读取的部分进行拼接
	panicLineLocated := false
	for _, stackLine := range strings.Split(string(buf), "\n") {
		if !panicLineLocated {
			if !strings.Contains(stackLine, "/runtime/panic.go") {
				// 丢弃runtime/panic.go之前的信息
				continue
			}
			panicLineLocated = true
			// panic行同样丢弃
			continue
		}
		if strings.HasPrefix(stackLine, "\t") {
			if methodCache == "grpc.(*Server).interceptor.func1" {
				// grpc拦截器trace可以跳过
				continue
			}
			stackLines = append(stackLines, fmt.Sprintf("%s %s",
				strings.Split(stackLine[1:], " +0x")[0], methodCache))
			if len(stackLines) > stackDepth {
				break
			}
		} else if strings.Contains(stackLine, "/") {
			pieces := strings.Split(stackLine, "/")
			methodCache = strings.Split(pieces[len(pieces)-1], "(0x")[0]
			if methodCache == "go-nsq.(*Consumer).handlerLoop" {
				// nsq终点
				break
			} else if strings.HasSuffix(methodCache, "_Handler.func1") {
				// grpc终点
				break
			}
		} else {
			continue
		}
	}
	return fmt.Sprintf("%s: panic recovered: %s\n%s", serviceName, r, strings.Join(stackLines, "\n"))
}
